home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / cut+paste < prev    next >
Encoding:
Internet Message Format  |  1987-02-23  |  26.7 KB

  1. Subject:  v08i078:  Public-domain implementations of cut(1) and paste(1)
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: pyramid!ptsfa!ptsfc!jgw (John Weald)
  6. Mod.sources: Volume 8, Issue 78
  7. Archive-name: cut+paste
  8.  
  9. Here is a verion of AT&T's cut and paste, it was not written from the source. 
  10. Cheers!
  11.     John Weald
  12.     {ihnp4, pyramid}!ptsfa!ptsfc!jgw
  13.  
  14. [  This also includes another re-implementaion of getopt.  --r$  ]
  15.  
  16. #! /bin/sh
  17. # This is a shell archive.  Remove anything before this line,
  18. # then unpack it by saving it in a file and typing "sh file".
  19. # If all goes well, you will see the message "End of shell archive."
  20. # Contents:  README cut.1 cut.c getopt.c makefile paste.1 paste.c
  21. #   spaste.c
  22. PATH=/bin:/usr/bin:/usr/ucb; export PATH
  23. echo shar: extracting "'README'" '(968 characters)'
  24. if test -f 'README' ; then 
  25.   echo shar: will not over-write existing file "'README'"
  26. else
  27. sed 's/^X//' >README <<'@//E*O*F README//'
  28. XThis is a public domain version of AT&T's cut and paste commands. Included is
  29. Xyet another version of getopt(3). If you already have a version then 
  30. Xchange the makefile.
  31. X
  32. XThe software has been tested on both 4.2BSD (CCI Power 6/32 aka Sperry 7000/40)
  33. Xand SVR2 (3b2/400). It is currently in production mode on 4.2.
  34. X
  35. XThe only known difference is that this cut does not require the list to be in 
  36. Xassending order.  e.g.
  37. X    cut -f4,2,1 x  <=>  cut -f1,2,4 x
  38. X
  39. XWhen a range is specified then the range must be in order e.g.
  40. X    cut -f3-2
  41. Xwill cause an error message.
  42. X    
  43. XDepending upon your point of view this may or may not be a 
  44. Xproblem.
  45. X
  46. XError messages are a little more helpful than in SVR1, in particular they 
  47. Xtell you what the limits are for line lenghts etc.
  48. X
  49. XFeel free to change the software, send any bug reports to
  50. X    {ihnp4, pyramid}!ptsfa!ptsfc!ccm   
  51. Xsince I am off the unix mail until the next assignment!!
  52. X
  53. XHave fun,
  54. X        John Weald
  55. X        AGS Computers, Inc.
  56. X        415-463-8711
  57. X
  58. @//E*O*F README//
  59. if test 968 -ne "`wc -c <'README'`"; then
  60.     echo shar: error transmitting "'README'" '(should have been 968 characters)'
  61. fi
  62. fi # end of overwriting check
  63. echo shar: extracting "'cut.1'" '(2652 characters)'
  64. if test -f 'cut.1' ; then 
  65.   echo shar: will not over-write existing file "'cut.1'"
  66. else
  67. sed 's/^X//' >cut.1 <<'@//E*O*F cut.1//'
  68. X.if t .ds ' \h@.05m@\s+4\v@.333m@\'\v@-.333m@\s-4\h@.05m@
  69. X.if n .ds ' '
  70. X.if t .ds ` \h@.05m@\s+4\v@.333m@\`\v@-.333m@\s-4\h@.05m@
  71. X.if n .ds ` `
  72. X.TH CUT 1
  73. X.SH NAME
  74. Xcut \- cut out selected fields of each line of a file
  75. X.SH SYNOPSIS
  76. X\fBcut \-c\fP\^list [\|file1 file2 ...]
  77. X.br
  78. X\fBcut \-f\fP\^list [\fB\-d\fP\|char\|] [\fB\-s\fP] [\|file1 file2 ...]
  79. X.SH DESCRIPTION
  80. XUse
  81. X.I cut\^
  82. Xto cut out columns from a table or 
  83. Xfields from each line of a file; in data base parlance, it implements
  84. Xthe projection of a relation.
  85. XThe fields as specified by
  86. X.I list\^
  87. Xcan be fixed length,
  88. Xi.e., character positions as on a punched card
  89. X(\fB\-c\fP option) or the length can vary from line to line
  90. Xand be marked with a field delimiter character like
  91. X.I tab\^
  92. X(\fB\-f\fP option).
  93. X.I Cut\^
  94. Xcan be used as a filter;
  95. Xif no files are given, the standard input is used.
  96. X.PP
  97. XThe meanings of the options are:
  98. X.br
  99. X.TP "\w'\-d\ char\ \ 'u"
  100. X.I list\^
  101. XA comma-separated 
  102. Xlist of integer field numbers,
  103. Xwith optional \fB\-\fP to indicate ranges
  104. Xas in the 
  105. X.B \-o
  106. Xoption of
  107. X.IR nroff / troff
  108. Xfor page ranges;
  109. Xe.g.,
  110. X.BR 1,4,7 ;
  111. X.BR 1\-3,8 ;
  112. X.B \-5,10
  113. X(short for \fB1\-5,10\fP); or
  114. X.B 3\-
  115. X(short for third through last field).
  116. X.TP
  117. X\fB\-c\fP\^\fIlist\fP
  118. XThe
  119. X.I list\^
  120. Xfollowing 
  121. X.B \-c
  122. Xspecifies character
  123. Xpositions (e.g.,
  124. X.B \-c1\-72
  125. Xwould pass the first 72 characters
  126. Xof each line).
  127. X.TP
  128. X\fB\-f\fP\^\fIlist\fP
  129. XThe \fIlist\fP following 
  130. X.B \-f
  131. Xis a list of fields
  132. Xassumed to be separated in the file by a delimiter character (see 
  133. X.B \-d
  134. X);
  135. Xe.g.,
  136. X.B \-f1,7
  137. Xcopies the first and seventh field only.
  138. XLines with no field delimiters will be passed through intact (useful
  139. Xfor table subheadings), unless 
  140. X.B \-s
  141. Xis specified.
  142. X.TP
  143. X\fB\-d\fP\^\fIchar\fP
  144. XThe character following 
  145. X.B \-d
  146. Xis the field delimiter
  147. X(\c
  148. X.B \-f
  149. Xoption only).
  150. XDefault is
  151. X.IR tab .
  152. XSpace or other characters with special meaning to the shell must be quoted.
  153. X.TP
  154. X.B \-s
  155. XSuppresses lines with no delimiter characters in case of
  156. X.B \-f
  157. Xoption.
  158. XUnless specified, lines with no delimiters will be passed through untouched.
  159. X.PP
  160. XEither the
  161. X.B \-c
  162. Xor 
  163. X.B \-f
  164. Xoption must be specified.
  165. X.SH HINTS
  166. XUse
  167. X.IR grep (1)
  168. Xto make horizontal ``cuts''
  169. X(by context) through a file, or
  170. X.IR paste (1)
  171. Xto put files together column-wise
  172. X(i.e., horizontally).
  173. XTo reorder columns in a table, use
  174. X.I cut\^
  175. Xand
  176. X.IR paste .
  177. X.SH EXAMPLES
  178. X.TP 2.25i
  179. Xcut \-d: \-f1,5 /etc/passwd
  180. Xmapping of user \s-1ID\s0s to names
  181. X.TP
  182. Xname=\*`who am i | cut \-f1 \-d" "\*`
  183. Xto set 
  184. X.B name
  185. Xto current login
  186. Xname.
  187. X.SH DIAGNOSTICS
  188. X.PP
  189. XError messages may come from getopt(3). All error messages contain limits
  190. Xfor line and field lenghts.
  191. X.SH SEE ALSO
  192. Xgrep(1),
  193. Xpaste(1).
  194. Xgetopt(3)
  195. @//E*O*F cut.1//
  196. if test 2652 -ne "`wc -c <'cut.1'`"; then
  197.     echo shar: error transmitting "'cut.1'" '(should have been 2652 characters)'
  198. fi
  199. fi # end of overwriting check
  200. echo shar: extracting "'cut.c'" '(4941 characters)'
  201. if test -f 'cut.c' ; then 
  202.   echo shar: will not over-write existing file "'cut.c'"
  203. else
  204. sed 's/^X//' >cut.c <<'@//E*O*F cut.c//'
  205. X/*
  206. X *  This acts the same as SV cut(1), except that the list of numbers
  207. X *  does not have to be assending.
  208. X *
  209. X * John Weald
  210. X */
  211. X#include <stdio.h>
  212. X#include <ctype.h>
  213. X
  214. X#define MAXLINE    1024        /* The max. length of a line        */
  215. X
  216. Xextern void exit();
  217. X
  218. Xmain(argc, argv)
  219. Xint argc;
  220. Xchar *argv[];
  221. X{
  222. X    extern char *optarg;
  223. X    extern int optind;
  224. X
  225. X    static int fields[MAXLINE];/* The field markers. True if this field */
  226. X                   /* is to be cut, False otherwise    */
  227. X    FILE *fp;           /* All the input files or stdin    */
  228. X    char buf[MAXLINE];       /* The input buffer            */
  229. X    int c;               /* The command line option        */
  230. X    int err = 0;           /* True if error in command line    */
  231. X    int fflag = 0;           /* True if -f on command line    */
  232. X    int cflag = 0;           /* True if -c on command line    */
  233. X    int suppress = 0;       /* Suppress lines with no delimitor    */
  234. X    char fs = '\t';           /* The field separator        */
  235. X
  236. X    
  237. X    while ((c = getopt(argc, argv, "f:d:c:s")) != EOF)
  238. X    {
  239. X        switch (c)
  240. X        {
  241. X           case 'f':
  242. X            /* By Field */
  243. X            list(fields, optarg);
  244. X            fflag++;
  245. X            if (cflag)
  246. X                err++;
  247. X            break;
  248. X
  249. X           case 'c':
  250. X            /* By character */
  251. X            list(fields, optarg);
  252. X            /* Implied suppress */
  253. X            suppress++;
  254. X            cflag++;
  255. X            if (fflag)
  256. X                err++;
  257. X            break;
  258. X
  259. X           case 'd':
  260. X            /* A new field spererator */
  261. X            fs = *optarg;
  262. X            break;
  263. X
  264. X           case 's':
  265. X            suppress++;
  266. X            break;
  267. X
  268. X           default:
  269. X            prusage();
  270. X        }
  271. X    }
  272. X
  273. X    if (!cflag && !fflag)
  274. X    {
  275. X        fprintf(stderr, "Must have one of -f or -c\n");
  276. X        err++;
  277. X    }
  278. X    if (err)
  279. X        prusage();
  280. X
  281. X
  282. X    /*
  283. X     * Loop on all the files.
  284. X     */
  285. X    do {
  286. X        if (optind == argc)
  287. X            fp = stdin;
  288. X        else if ((fp = fopen(argv[optind], "r")) == (FILE *)NULL)
  289. X        {
  290. X            fprintf(stderr, "Failed to open file %s\n", 
  291. X                    argv[optind]);
  292. X            exit(1);
  293. X        }
  294. X
  295. X        /*
  296. X         * Loop on all lines in the file.
  297. X         */
  298. X        while (fgets(buf, sizeof(buf), fp) != (char *)NULL)
  299. X        {
  300. X            cut(buf, fields, fs, suppress, cflag);
  301. X        }
  302. X        (void)fclose(fp);
  303. X    } while (++optind < argc);
  304. X
  305. X    exit(0);
  306. X/* NOTREACHED */
  307. X}
  308. X
  309. X/*
  310. X * Cut the line. This handles both character and field cutting.
  311. X * For character cutting the f array gives character positions, for
  312. X * fields it gives the field number. It must be indexed by either the
  313. X * character number or the field number.
  314. X */
  315. Xcut(in, f, fs, sup, c_or_f)
  316. Xregister char *in;        /* The input line            */
  317. Xint f[];            /* The field cutting flags        */
  318. Xchar fs;            /* The field seperator            */
  319. Xint sup;            /* Suppress lines with no-delimitor?    */
  320. Xint c_or_f;            /* Cut by char. (true), or field (false)*/
  321. X{
  322. X    char obuf[MAXLINE];    /* Output buffer            */
  323. X    register char *optr = obuf;
  324. X    register int i;        /* Character count            */
  325. X    register int fld;    /* The field count            */
  326. X    char *instart = in;    /* To print lines with no delimiters    */
  327. X
  328. X    for (fld = 0, i = 0; i < MAXLINE; i++)
  329. X    {
  330. X        if (*in == '\n')
  331. X        {
  332. X            /* End of the line */
  333. X
  334. X            *optr = '\0';
  335. X            /* Any thing to cut? */
  336. X            if (optr != obuf)
  337. X            {
  338. X                /* Get ride of trailing seperator */
  339. X                if (*(optr - 1) == fs)
  340. X                    *(optr - 1) = '\0';
  341. X                puts(obuf);
  342. X            }
  343. X            else if (!sup)
  344. X                printf(instart);
  345. X            return;
  346. X        }
  347. X
  348. X        if (f[c_or_f ? i : fld])
  349. X        {
  350. X            *optr++ = *in;
  351. X        }
  352. X
  353. X        /* End of field? */
  354. X        if (*in++ == fs)
  355. X            fld++;
  356. X    }
  357. X
  358. X    fprintf(stderr, "Line too long, maximum length is %d\n", MAXLINE);
  359. X    exit(1);
  360. X}
  361. X
  362. X/*
  363. X * Parse the list argument. The format is:
  364. X *    n,n
  365. X * where n is either a number or a range of numbers in the format
  366. X *    m-l
  367. X * m or l  may be absent, indicating the start or end of the lines respectivly.
  368. X * Numbers must be in increasing order for m-l format, but not for n,n.
  369. X * Field numbers start at 1, but index into fields array starts at 0.
  370. X * 
  371. X */
  372. Xlist(f, l)
  373. Xint f[];        /* The fields                */
  374. Xchar *l;        /* The list                */
  375. X{
  376. X    int range = 0;    /* True if m-l format             */
  377. X    int low, high;    /* the low and high numbers in a m-l pair*/
  378. X    int i;
  379. X
  380. X    low = high = 0;
  381. X
  382. X    while (1)
  383. X    {
  384. X        switch(*l)
  385. X        {
  386. X           case '\0':
  387. X            /* Is it m-<nothing>EOL? */
  388. X            if (range)
  389. X            {
  390. X                /* Select rest of fields */
  391. X                for(i = low - 1; i < MAXLINE; i++)
  392. X                    f[i]++;
  393. X            }
  394. X            else
  395. X                f[low-1]++;
  396. X            return;
  397. X
  398. X           case ',':
  399. X            l++;
  400. X            if (!range)
  401. X                f[low-1]++;
  402. X            range = 0;
  403. X            low = 1;
  404. X            break;
  405. X
  406. X           case '-':
  407. X            l++;
  408. X            range++;
  409. X            /* Is it m-<nothing> */
  410. X            if (isdigit((int)*l))
  411. X            {
  412. X                high = atoi(l);
  413. X                /* Skip the digits */
  414. X                while (isdigit((int) *l))
  415. X                    l++;
  416. X            }
  417. X            else
  418. X                high = MAXLINE;
  419. X
  420. X            /* Is the range the correct way around? */
  421. X            if (low > high)
  422. X            {
  423. X                fprintf(stderr, "Bad c/f list: %d > %d\n", 
  424. X                            low, high);
  425. X                exit(1);
  426. X            }
  427. X            /* Set the field flags for the range */
  428. X            for(i = low - 1; i < high; i++)
  429. X                f[i]++;
  430. X            break;
  431. X
  432. X            default:
  433. X            /* either a number or an error */
  434. X            if (!isdigit((int) *l))
  435. X            {
  436. X                fprintf(stderr, "Bad c/f list at %s\n", l);
  437. X                exit(1);
  438. X            }
  439. X            low = atoi(l);
  440. X            if (low == 0)
  441. X            {
  442. X                fprintf(stderr, "Fields start at 1 not 0\n");
  443. X                exit(1);
  444. X            }
  445. X            /* Skip the digits */
  446. X            while (isdigit((int) *l))
  447. X                l++;
  448. X            break;
  449. X        }
  450. X    }
  451. X}
  452. X
  453. Xprusage()
  454. X{
  455. X    fprintf(stderr, "cut [-d<delimitor>] [-s] -c<list>|-f<list> [files]\n");
  456. X    exit(1);
  457. X}
  458. @//E*O*F cut.c//
  459. if test 4941 -ne "`wc -c <'cut.c'`"; then
  460.     echo shar: error transmitting "'cut.c'" '(should have been 4941 characters)'
  461. fi
  462. fi # end of overwriting check
  463. echo shar: extracting "'getopt.c'" '(3739 characters)'
  464. if test -f 'getopt.c' ; then 
  465.   echo shar: will not over-write existing file "'getopt.c'"
  466. else
  467. sed 's/^X//' >getopt.c <<'@//E*O*F getopt.c//'
  468. X/*
  469. X * getopt(), a verson of getopt for those who do not have it and do not
  470. X * want to steal the source from those that do.
  471. X *
  472. X * Same as getopt(3).
  473. X *    Returns the next option letter in argv that matches a letter in optstr.
  474. X *    Options are no longer parsed if the special option '--' is found
  475. X *    or an argument that does not start in '-'.
  476. X *    The global optind is set to the next index in argv to be processed.
  477. X *    The global optarg is set to the argument, if the option has one.
  478. X *    The global opterr can be set true if error messages are to be printed
  479. X *    on the standard error file, or false if no message to be printed.
  480. X *
  481. X * ARGUMENTS:
  482. X *    argc, argv - the argument count, and argument list
  483. X *    optstr     - the list of valid options. The character ":" following
  484. X *             an option letter indicates that this option must have an 
  485. X *             argument. For example "abc:". This implies that the -:
  486. X *             is not  a valid option.
  487. X *
  488. X * RETURNS:
  489. X *    Returns the next option letter, or EOF when all done. If an error
  490. X *    encountered then the character '?' is returned.
  491. X *
  492. X * John Weald
  493. X */
  494. X#include <stdio.h>
  495. X
  496. X/*
  497. X * Index into error array.
  498. X */
  499. X#define BAD_OPT 0    /* option letter not in optstr            */
  500. X#define MIS_ARG 1    /* option must have an argument            */
  501. X
  502. Xchar *optarg;
  503. Xint optind = 1;        /* argv[0] is program name            */
  504. Xint opterr = 1;        /* If true print error message            */
  505. X
  506. X/*
  507. X *
  508. X * The basic data structures are optind, and the pointer "p."
  509. X * optind keeps track of the next index into argv to parse arguments.
  510. X * p is used to walk along the argv items looking for option letters or
  511. X * arguments, when it is NULL the next  argv must be used . 
  512. X * p is always left pointing to the previous option or NULL.
  513. X * Consider the three equivalent valid argv's:
  514. X *        1        2         3
  515. X *        -a     -b       eric
  516. X *            -ab    eric
  517. X *        -aberic
  518. X * 
  519. X */
  520. X
  521. Xint
  522. Xgetopt(argc, argv, optstr)
  523. Xint argc;
  524. Xchar *argv[];
  525. Xchar *optstr;        /* The list of valid options            */
  526. X{
  527. X    extern void err();    /* Forward reference            */
  528. X
  529. X    static char *p = (char *)NULL;
  530. X
  531. X    /*
  532. X     * parsed all the options in this argv[]?
  533. X     */
  534. X    if (p == NULL || *++p == '\0' )
  535. X    {
  536. X        if (optind == argc)
  537. X            return(EOF);
  538. X        p = argv[optind];
  539. X
  540. X        /*  a '-' by itself is not an option (e.g. see paste(1)) */
  541. X        if (*p++ != '-' || *p == '\0') 
  542. X            return(EOF);
  543. X
  544. X        /* '--' marks the end of the option list.  */
  545. X        if (*p == '-')
  546. X        {
  547. X            optind++;
  548. X            return(EOF);
  549. X        }
  550. X    }
  551. X
  552. X    optind++;
  553. X    /*
  554. X     * Look for a valid option 
  555. X     */
  556. X    while (*p != *optstr)
  557. X    {    
  558. X        if (*optstr == '\0')
  559. X        {
  560. X            /* Reached end of optstr, option not there */
  561. X            err(argv[0], BAD_OPT, *p);
  562. X            return((int)'?');
  563. X        }
  564. X        if (*++optstr == ':')
  565. X            optstr++;
  566. X    }
  567. X
  568. X    /* If it does not need an argument then we are done.  */
  569. X    if (*(optstr + 1) != ':')
  570. X        return((int)*optstr);
  571. X    
  572. X    /*
  573. X     * If there are more characters in this argv then it must
  574. X     * be the argument.
  575. X     */
  576. X    if (*++p != '\0')
  577. X    {
  578. X        optarg = p;
  579. X        p = (char *)NULL;
  580. X        return((int)*optstr);
  581. X    }
  582. X
  583. X    /* 
  584. X     * It needs an argument, but no more argv's left
  585. X     */
  586. X    if (optind == argc)
  587. X    {
  588. X        err(argv[0], MIS_ARG, *optstr);
  589. X        p = (char *)NULL;
  590. X        return((int)'?');
  591. X    }
  592. X
  593. X    /*
  594. X     * Must be in next argv.
  595. X     */
  596. X    optarg = argv[optind++];
  597. X    p = (char *)NULL;
  598. X    return((int)*optstr);
  599. X}
  600. X
  601. Xstatic void
  602. Xerr(a0, e, c)
  603. Xchar *a0;        /* argv[0]. i.e. the program name        */
  604. Xint e;
  605. Xchar c;
  606. X{
  607. X#ifdef NO_STDIO
  608. X    static char *errors[] = {
  609. X        ": Illegal option -- ",
  610. X        ": option requires an argument -- "
  611. X    };
  612. X    static char eend[] = "c\n";
  613. X    
  614. X
  615. X    if (opterr)
  616. X    {
  617. X        (void)write(2, a0, strlen(a0));
  618. X        (void)write(2, errors[e], strlen(errors[e]));
  619. X        eend[0] = c;
  620. X        (void)write(2, eend, strlen(eend));
  621. X    }
  622. X#else
  623. X    static char *errors[] = {
  624. X        "%s: Illegal option -- %c\n",
  625. X        "%s: option requires an argument -- %c\n"
  626. X    };
  627. X
  628. X    if (opterr)
  629. X        fprintf(stderr, errors[e], a0, c);
  630. X#endif
  631. X}
  632. @//E*O*F getopt.c//
  633. if test 3739 -ne "`wc -c <'getopt.c'`"; then
  634.     echo shar: error transmitting "'getopt.c'" '(should have been 3739 characters)'
  635. fi
  636. fi # end of overwriting check
  637. echo shar: extracting "'makefile'" '(241 characters)'
  638. if test -f 'makefile' ; then 
  639.   echo shar: will not over-write existing file "'makefile'"
  640. else
  641. sed 's/^X//' >makefile <<'@//E*O*F makefile//'
  642. Xall: cut paste
  643. X
  644. X
  645. Xpaste: paste.o spaste.o getopt.o
  646. X    cc -o paste paste.o spaste.o getopt.o
  647. X
  648. Xcut: cut.o getopt.o
  649. X    cc -o cut cut.o getopt.o
  650. X
  651. Xlint: lint_cut lint_paste
  652. X
  653. Xlint_cut:
  654. X    lint cut.c getopt.c
  655. X
  656. Xlint_paste:
  657. X    lint paste.c spaste.c getopt.c
  658. X
  659. @//E*O*F makefile//
  660. if test 241 -ne "`wc -c <'makefile'`"; then
  661.     echo shar: error transmitting "'makefile'" '(should have been 241 characters)'
  662. fi
  663. fi # end of overwriting check
  664. echo shar: extracting "'paste.1'" '(2608 characters)'
  665. if test -f 'paste.1' ; then 
  666.   echo shar: will not over-write existing file "'paste.1'"
  667. else
  668. sed 's/^X//' >paste.1 <<'@//E*O*F paste.1//'
  669. X.TH PASTE 1
  670. X.SH NAME
  671. Xpaste \- merge same lines of several files or subsequent lines of one file
  672. X.SH SYNOPSIS
  673. X\f3paste \fPfile1 file2 .\|.\|.
  674. X.br
  675. X\f3paste \-d\fP\|list file1 file2 .\|.\|.
  676. X.br
  677. X\f3paste \-s [\-d\fP\|list\|\f3] \fPfile1 file2 .\|.\|.
  678. X.SH DESCRIPTION
  679. XIn the first two forms,
  680. X.I paste\^
  681. Xconcatenates corresponding lines of the given input
  682. Xfiles
  683. X.IR file1 ,
  684. X.IR file2 ,
  685. Xetc.
  686. XIt treats each file as a column or columns
  687. Xof a table and pastes them together horizontally
  688. X(parallel merging).
  689. XIf you will, it is
  690. Xthe counterpart of
  691. X.IR cat (1)
  692. Xwhich concatenates vertically, i.e.,
  693. Xone file after the other.
  694. XIn the last form above,
  695. X.I paste\^
  696. Xreplaces the function of an older command with the same name
  697. Xby combining subsequent lines of the input file (serial merging).
  698. XIn all cases,
  699. Xlines are glued together with the
  700. X.I tab\^
  701. Xcharacter,
  702. Xor with characters from an optionally specified
  703. X.IR list .
  704. XOutput is to the standard output, so it can be used as
  705. Xthe start of a pipe,
  706. Xor as a filter,
  707. Xif \f3\-\fP is used in place of a file name.
  708. X.PP
  709. XThe meanings of the options are:
  710. X.TP
  711. X.B "\-d"
  712. XWithout this option,
  713. Xthe new-line characters of each but the last file
  714. X(or last line in case of the
  715. X.B \-s
  716. Xoption)
  717. Xare replaced
  718. Xby a
  719. X.I tab\^
  720. Xcharacter.
  721. XThis option allows replacing the
  722. X.I tab\^
  723. Xcharacter by one or more alternate characters (see below).
  724. X.TP
  725. X.I "list\^"
  726. XOne or more characters immediately following
  727. X.B \-d
  728. Xreplace the default
  729. X.I tab\^
  730. Xas the line concatenation character.
  731. XThe list is used circularly, i.e., when exhausted, it is reused.
  732. XIn parallel merging (i.e., no
  733. X.B \-s
  734. Xoption),
  735. Xthe lines from the last file are always terminated with a new-line character,
  736. Xnot from the
  737. X.IR list .
  738. XThe list may contain the special escape sequences:
  739. X.B \en
  740. X(new-line),
  741. X.B \et
  742. X(tab),
  743. X.B \e\e
  744. X(backslash), and
  745. X.B \e0
  746. X(empty string, not a null character).
  747. XQuoting may be necessary, if characters have special meaning to the shell
  748. X(e.g., to get one backslash, use
  749. X.I \-d\|"\e\e\e\e\^"
  750. X).
  751. X.TP
  752. X.B "\-s"
  753. XMerge subsequent lines rather than one from each input file.
  754. XUse
  755. X.I tab\^
  756. Xfor concatenation, unless a
  757. X.I list\^
  758. Xis specified
  759. Xwith
  760. X.B \-d
  761. Xoption.
  762. XRegardless of the
  763. X.IR list ,
  764. Xthe very last character of the file is forced to be a new-line.
  765. X.TP
  766. X.B "\-"
  767. XMay be used in place of any file name,
  768. Xto read a line from the standard input.
  769. X(There is no prompting).
  770. X.SH EXAMPLES
  771. X.TP 15m
  772. Xls \|\(bv\| paste \|\-d" " \|\-
  773. Xlist directory in one column
  774. X.TP
  775. Xls \|\(bv\| paste \|\- \|\- \|\- \|\-
  776. Xlist directory in four columns
  777. X.TP
  778. Xpaste \|\-s \|\-d"\e\|t\e\|n" \|file
  779. Xcombine pairs of lines into lines
  780. X.SH "SEE ALSO"
  781. Xcut(1), grep(1), pr(1).
  782. @//E*O*F paste.1//
  783. if test 2608 -ne "`wc -c <'paste.1'`"; then
  784.     echo shar: error transmitting "'paste.1'" '(should have been 2608 characters)'
  785. fi
  786. fi # end of overwriting check
  787. echo shar: extracting "'paste.c'" '(4780 characters)'
  788. if test -f 'paste.c' ; then 
  789.   echo shar: will not over-write existing file "'paste.c'"
  790. else
  791. sed 's/^X//' >paste.c <<'@//E*O*F paste.c//'
  792. X/*
  793. X * A version of paste. This is compatable with AT&T paste command SVR2.
  794. X *
  795. X * John Weald
  796. X *
  797. X */
  798. X#include <stdio.h>
  799. X
  800. X#define MAXLINE   1024            /* Max. allowed line length    */
  801. X#define MAXFILES  12            /* Max. number of input files   */
  802. X
  803. Xextern void exit();
  804. X
  805. Xmain(argc, argv)
  806. Xint argc;
  807. Xchar *argv[];
  808. X{
  809. X    extern int optind;
  810. X    extern char *optarg;
  811. X
  812. X    int c;                /* For getopt()            */
  813. X    char conchars[MAXFILES];    /* The concatination characters */
  814. X    int nconchars = 1;        /* The number of conchars[]    */
  815. X    int serial = 0;            /* True if old type paste "-s"    */
  816. X
  817. X    conchars[0] = '\t';
  818. X
  819. X    while ((c = getopt(argc, argv, "sd:")) != EOF)
  820. X    {
  821. X        switch(c)
  822. X        {
  823. X           case 's':
  824. X            /* Concatinate the same file serially */
  825. X            serial++;
  826. X            break;
  827. X
  828. X           case 'd':
  829. X            /* Use other than a single tab */
  830. X            nconchars = setconcat(conchars, optarg);
  831. X            break;
  832. X
  833. X           default:
  834. X            /* Does not return */
  835. X            prusage();
  836. X        }
  837. X    }
  838. X
  839. X
  840. X    if (serial)
  841. X        spaste(&argv[optind], conchars, nconchars);
  842. X    else
  843. X        paste(&argv[optind], conchars, nconchars);
  844. X    exit(0);
  845. X/* NOTREACHED */
  846. X}
  847. X
  848. X
  849. X
  850. X/*
  851. X * paste()
  852. X *
  853. X * Do the actual paste.
  854. X */
  855. Xpaste(files, con, ncons)
  856. Xchar *files[];        /* Null terminated list of input files        */
  857. Xchar con[];        /* The concatination characters            */
  858. Xchar ncons;        /* The number of above                */
  859. X{
  860. X    char ibuf[MAXLINE+1];        /* The  input buffer        */
  861. X    char obuf[MAXLINE];        /* The  output buffer        */
  862. X    register char *iptr = ibuf;
  863. X    register char *optr = obuf;
  864. X    FILE *fps[MAXFILES];        /* One for each open file     */
  865. X    int f;                /* Number of files opened    */
  866. X    int allfiles;            /* Ditto            */
  867. X    int inc;            /* True if concat. char. == '\0'*/
  868. X    int ocount;            /* Output buffer char. count    */
  869. X    char c;                /* The current concat. char    */
  870. X    int i;
  871. X
  872. X    /*
  873. X     * Open all the input files, any filename of '-' means
  874. X     * the standard input. No file name means standard input.
  875. X     */
  876. X    for (f = 0; files[f] != (char *)NULL; f++)
  877. X    {
  878. X        if (*files[f] == '-')
  879. X            fps[f] = stdin;
  880. X        else if ((fps[f] = fopen(files[f], "r")) == (FILE *)NULL)
  881. X        {
  882. X            fprintf(stderr, "Failed to open file %s\n", files[f]);
  883. X            exit(1);
  884. X        }
  885. X        if (f >= MAXFILES)
  886. X        {
  887. X            fprintf(stderr, 
  888. X               "Too many files. Maximum allowed is %d\n", MAXFILES);
  889. X            exit(1);
  890. X        }
  891. X    } 
  892. X    if (files[0] == (char *)NULL)
  893. X    {
  894. X        fps[0] = stdin;
  895. X        f++;
  896. X    }
  897. X
  898. X    /*
  899. X     * Read all lines until no more lines in any file.
  900. X     */
  901. X    allfiles = f;
  902. X    while (f)
  903. X    {
  904. X        optr = obuf;
  905. X        ocount = 0;
  906. X        /*
  907. X         * Join lines from all files.
  908. X         *
  909. X         * The concatination character may be '\0' which
  910. X         * means no character. The variable inc is an indication
  911. X         * of the concatination character being '\0', we need to
  912. X         * if there is a concatination character to move up the
  913. X         * output buffer.
  914. X         *
  915. X         * The concatination characters are used in a round robin
  916. X         * list.
  917. X         */
  918. X
  919. X        for (inc = 0, i = 0; i < allfiles; i++)
  920. X        {
  921. X            iptr = ibuf;
  922. X            optr += inc;
  923. X            /* To save repeated evaluation */
  924. X            c = con[i % ncons];
  925. X            inc = c == '\0' ? 0 : 1;
  926. X
  927. X            if (fps[i] == (FILE *)NULL)
  928. X            {
  929. X                /* No more lines in this file. */
  930. X
  931. X                *optr = c;
  932. X                continue;
  933. X            }
  934. X            if (fgets(ibuf, sizeof(ibuf), fps[i]) == (char *)NULL)
  935. X            {
  936. X                /* Reached EOF - finished with the file */
  937. X                (void)fclose(fps[i]);
  938. X                fps[i] = (FILE *)NULL;
  939. X                *optr = c;
  940. X                f--;
  941. X                continue;
  942. X            }
  943. X
  944. X            /*
  945. X             * Replace the newline with the concatination character.
  946. X             * There is no need to look for end-of-string since
  947. X             * we know that 
  948. X             * a) if ibuf is full to the max, then we will
  949. X             *    overflow obuf before we hit the end of ibuf.
  950. X             * b) if ibuf is not full, then it must contain a
  951. X             *    a newline character, but may or may not  
  952. X             *    fit into obuf.
  953. X             */
  954. X            for (;  *iptr != '\n'; ocount++)
  955. X            {
  956. X                /* Need space for trailing null */
  957. X                if (ocount >= sizeof(obuf) - 1)
  958. X                {
  959. X                    fprintf(stderr, "Output line too long, maximum length is %d.\n", MAXLINE);
  960. X                    exit(1);
  961. X                }
  962. X                *optr++ = *iptr++;
  963. X            }
  964. X            *optr = c;
  965. X
  966. X        }
  967. X        if (f)
  968. X        {
  969. X            *optr = '\0';
  970. X            puts(obuf);
  971. X        }
  972. X    }
  973. X}
  974. X
  975. X
  976. X/*
  977. X * setconcat()
  978. X *
  979. X * Parse the concatination characters and place them in the array c.
  980. X * Return the number of concatination characters.
  981. X *
  982. X * Specials are:
  983. X *    \n    - Newline
  984. X *    \t    - Tab (default)
  985. X *    \    - Backslash
  986. X *    \0    - No concatination character
  987. X */
  988. Xstatic int
  989. Xsetconcat(c, in)
  990. Xchar *c;
  991. Xchar *in;
  992. X{
  993. X    int i;        /* The number seen so far            */
  994. X
  995. X    for (i = 0; *in != '\0'; in++, c++, i++)
  996. X    {
  997. X        if (i > MAXFILES)
  998. X        {
  999. X            fprintf(stderr, "Too many concatination characters, maximum allowed is %d\n", MAXFILES);
  1000. X            exit(1);
  1001. X        }
  1002. X        if (*in != '\\')
  1003. X        {
  1004. X            *c = *in;
  1005. X            continue;
  1006. X        }
  1007. X        in++;
  1008. X        switch (*in)
  1009. X        {
  1010. X           case 'n':
  1011. X            *c = '\n';
  1012. X            break;
  1013. X           case 't':
  1014. X            *c = '\t';
  1015. X            break;
  1016. X           case '0':
  1017. X            *c = '\0';
  1018. X            break;
  1019. X           default:
  1020. X            /* Includes '\\' */
  1021. X            *c = *in;
  1022. X            break;
  1023. X        }
  1024. X    }
  1025. X    return(i);
  1026. X}
  1027. X
  1028. Xstatic 
  1029. Xprusage()
  1030. X{
  1031. X    fprintf(stderr, "USAGE: paste [-s] [-d<list>] files\n");
  1032. X    exit(1);
  1033. X}
  1034. @//E*O*F paste.c//
  1035. if test 4780 -ne "`wc -c <'paste.c'`"; then
  1036.     echo shar: error transmitting "'paste.c'" '(should have been 4780 characters)'
  1037. fi
  1038. fi # end of overwriting check
  1039. echo shar: extracting "'spaste.c'" '(2641 characters)'
  1040. if test -f 'spaste.c' ; then 
  1041.   echo shar: will not over-write existing file "'spaste.c'"
  1042. else
  1043. sed 's/^X//' >spaste.c <<'@//E*O*F spaste.c//'
  1044. X/*
  1045. X * Serially paste a file together
  1046. X *
  1047. X * John Weald
  1048. X */
  1049. X#include <stdio.h>
  1050. X
  1051. Xextern void exit();
  1052. X
  1053. X
  1054. Xspaste(files, c, n)
  1055. Xchar *files[];        /* Null terminate list of input files        */
  1056. Xchar c[];        /* The concatintaion characters            */
  1057. Xint n;            /* The number of above                */
  1058. X{
  1059. X    int i;
  1060. X    FILE *fp;
  1061. X
  1062. X    if (files[0] == (char *)NULL)
  1063. X    {
  1064. X        spfile(stdin, c, n);
  1065. X        return;
  1066. X    }
  1067. X
  1068. X    for (i = 0; files[i] != (char *)NULL; i++)
  1069. X    {
  1070. X        if (*files[i] == '-')
  1071. X            fp = stdin;
  1072. X        else if ((fp = fopen(files[i], "r")) == (FILE *)NULL)
  1073. X        {
  1074. X            fprintf(stderr, "Failed to open file %s\n", files[i]);
  1075. X            exit(1);
  1076. X        }
  1077. X        spfile(fp, c, n);
  1078. X        (void)fclose(fp);
  1079. X    }
  1080. X}
  1081. X    
  1082. X/* 
  1083. X * Do the actual paste of a stream.
  1084. X *
  1085. X * The method here is to read in the stream and replace all newline
  1086. X * characters with concatintaion characters. 
  1087. X * Output occurs after each chuck is parsed, or if the concatination character
  1088. X * is the null seperator (otherwise puts() would screw up on whole chunk).
  1089. X *
  1090. X * The stream is read in BUFSIZ chunks using fread. The input buffer is one
  1091. X * larger than read, so that it can be null terminated. 
  1092. X *
  1093. X * When we read in each chunk we must check if it needs to be joined to the
  1094. X * previous one i.e. the last character on the last chunk was a newline.
  1095. X */
  1096. Xstatic
  1097. Xspfile(fp, con, ncons)
  1098. XFILE *fp;        /* serially paste this stream            */
  1099. Xchar con[];        /* The concatintaion characters            */
  1100. Xint ncons;        /* The number of above                */
  1101. X{
  1102. X    char *pstart;    /* The start of the string            */
  1103. X    char *ptr;    /* Walks down the stream            */
  1104. X    char buf[BUFSIZ + 1]; /* To ensure null termination        */
  1105. X    int n;        /* Number of bytes read with fread()        */
  1106. X    int k = 0;    /* Index into concatination character array    */
  1107. X    int join;    /* Join this chunk to the next?            */
  1108. X    char last;    /* The very last character looked at.        */
  1109. X
  1110. X
  1111. X    join = 0;
  1112. X    while ((n = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) != 0)
  1113. X    {
  1114. X        if (join)
  1115. X        {
  1116. X            /* Join with last chunk */
  1117. X            putchar(con[k]);
  1118. X            k = (k + 1) % ncons;
  1119. X            join = 0;
  1120. X        }
  1121. X        /* Join to next chunk? */
  1122. X        if (buf[n-1] == '\n')
  1123. X        {
  1124. X            join++;
  1125. X            /* Ignore the newline */
  1126. X            n--;
  1127. X        }
  1128. X
  1129. X        /* ensure null terminated buffer */
  1130. X        buf[n] = '\0';
  1131. X
  1132. X        
  1133. X        /* 
  1134. X          * walk thru this chunk 
  1135. X         * replace all newlines with the next concat. char.
  1136. X         */
  1137. X        for (pstart = ptr = buf; *ptr != '\0'; ptr++)
  1138. X        {
  1139. X            if (*ptr == '\n')
  1140. X            {
  1141. X                *ptr = con[k];
  1142. X                if (con[k] == '\0')
  1143. X                {
  1144. X                    fputs(pstart, stdout);
  1145. X                    pstart = ptr + 1;
  1146. X                }
  1147. X                k = (k + 1) % ncons;
  1148. X            }
  1149. X        }
  1150. X        fputs(pstart, stdout);
  1151. X
  1152. X        last = *(ptr - 1);
  1153. X    }
  1154. X
  1155. X    /*
  1156. X     * Maybe they asked for the newline as the
  1157. X     * concatination char. We would hate to give them two newlines
  1158. X     * in a row.
  1159. X     */
  1160. X    if (last != '\n')
  1161. X        putchar('\n');
  1162. X}
  1163. @//E*O*F spaste.c//
  1164. if test 2641 -ne "`wc -c <'spaste.c'`"; then
  1165.     echo shar: error transmitting "'spaste.c'" '(should have been 2641 characters)'
  1166. fi
  1167. fi # end of overwriting check
  1168. echo shar: "End of shell archive."
  1169. exit 0
  1170.